// ExecutionDlg.cpp : implementation file
//

#include "stdafx.h"
#include "LightspeedTraderAPIDemo.h"
#include "ExecutionDlg.h"

//C_Execution

class C_Execution
{
public:
      C_Execution(L_Execution const &exec)
            : side(exec.L_Side())
            , shares(exec.L_Shares())
            , isOvernight(exec.L_IsOvernight())
            , totalPrice(exec.L_TotalPrice())
            , averagePrice(exec.L_AveragePrice())
            , moneyInvested(exec.L_MoneyInvested())
            , liquidity(exec.L_Liquidity())
            , market(exec.L_Market())
            , contra(exec.L_Contra())
			, executionTime(exec.L_ExecTime())
			, executionTimeMillis(exec.L_ExecTimeMillis())
      {
      }
      C_Execution(L_Execution const *exec)
            : side(exec->L_Side())
            , shares(exec->L_Shares())
            , isOvernight(exec->L_IsOvernight())
            , totalPrice(exec->L_TotalPrice())
            , averagePrice(exec->L_AveragePrice())
            , moneyInvested(exec->L_MoneyInvested())
            , liquidity(exec->L_Liquidity())
            , market(exec->L_Market())
            , contra(exec->L_Contra())
			, executionTime(exec->L_ExecTime())
			, executionTimeMillis(exec->L_ExecTimeMillis())
      {
      }
      C_Execution(C_Execution const &rhs)
            : side(rhs.side)
            , shares(rhs.shares)
            , isOvernight(rhs.isOvernight)
            , totalPrice(rhs.totalPrice)
            , averagePrice(rhs.averagePrice)
            , moneyInvested(rhs.moneyInvested)
            , liquidity(rhs.liquidity)
            , market(rhs.market)
            , contra(rhs.contra)
			, executionTime(rhs.executionTime)
			, executionTimeMillis(rhs.executionTimeMillis)
      {
      }
      char Side() const
      {
            return side;
      }
      long Shares() const
      {
            return shares;
      }
      bool IsOvernight() const
      {
            return isOvernight;
      }

      std::string const &Market() const
      {
            return market;
      }
      std::string const &Contra() const
      {
            return contra;
      }
      char Liquidity() const
      {
            return liquidity;
      }

      double TotalPrice() const
      {
            return totalPrice;
      }
      double AveragePrice() const
      {
            return averagePrice;
      }
      double MoneyInvested() const
      {
            return moneyInvested;
      }

	  time_t ExecutionTime() const
	  {
		  return executionTime;
	  }

	  long ExecutionTimeMillis() const
	  {
		  return executionTimeMillis;
	  }

private:
      double totalPrice;
      double averagePrice;
      double moneyInvested;
      long shares;
      char side;
      char liquidity;
      bool isOvernight;
      std::string market;
      std::string contra;
	  time_t executionTime;
	  long executionTimeMillis;
};

enum EXECUTION_VALUES {
	TOTAL_PRICE,
	AVERAGE_PRICE,
	MONEY_INVESTED,
	SHARES,
	SIDE,
	LIQUIDITY,
	IS_OVERNIGHT,
	MARKET,
	CONTRA,
	EXECUTION_TIME,
	EXECUTION_TIME_MILLIS,

	END_OF_VALUES
};


// ExecutionDlg dialog

IMPLEMENT_DYNAMIC(ExecutionDlg, CModelessDialog)

ExecutionDlg::ExecutionDlg(CWnd* pParent /*=NULL*/)
	: CModelessDialog(ExecutionDlg::IDD, pParent)
	, position(NULL)
	, order(NULL)
	, m_ExecDataListCtrl(CListCtrl())
	, m_ExecCombo(CComboBox())
	, m_ExecutionsSrc(NO_SRC)
	, m_DispType(ALL_EXEC)
	, m_pExecution(NULL)
{
	SetAPIFunctions();
}

ExecutionDlg::ExecutionDlg(L_Position *p, CWnd* pParent /*= NULL*/)
	: CModelessDialog(ExecutionDlg::IDD, pParent)
	, position(p)
	, order(NULL)
	, m_ExecDataListCtrl(CListCtrl())
	, m_ExecCombo(CComboBox())
	, m_ExecutionsSrc(POSITION_EXECUTIONS)
	, m_DispType(ALL_EXEC)
	, m_pExecution(NULL)
{
	SetAPIFunctions();
}

ExecutionDlg::ExecutionDlg(L_Order *o, CWnd* pParent /*= NULL*/)
	: CModelessDialog(ExecutionDlg::IDD, pParent)
	, position(NULL)
	, order(o)
	, m_ExecDataListCtrl(CListCtrl())
	, m_ExecCombo(CComboBox())
	, m_ExecutionsSrc(ORDER_EXECUTIONS)
	, m_DispType(ALL_EXEC)
	, m_pExecution(NULL)
{
	SetAPIFunctions();
}

ExecutionDlg::~ExecutionDlg()
{
	if (account)
	{
		account->L_Detach(this);
	}

	if (position)
	{
		position = NULL;
	}

	if (order)
	{
		order = NULL;
	}

	if (m_pExecution)
	{
		delete m_pExecution;
		m_pExecution = NULL;
	}
}

BOOL ExecutionDlg::Create(CWnd *pParentWnd /*= CWnd::FromHandle(L_GetMainWnd())*/)
{
	return __super::Create(ExecutionDlg::IDD, pParentWnd);
}

BOOL ExecutionDlg::OnInitDialog()
{
	__super::OnInitDialog();

	CString title = "View Execution ";
	switch (m_ExecutionsSrc)
	{
	case POSITION_EXECUTIONS:
		title += "Position - ";
		title += position->L_Symbol();
		break;
	case ORDER_EXECUTIONS:
		title += "Order - ";
		CString id;
		id.Format("%d", order->L_OrderId());
		title += id;
		break;
	}
	SetWindowText(title);

	if (m_ExecutionsSrc == ORDER_EXECUTIONS)
	{
		GetDlgItem(IDC_BUYRADIO)->EnableWindow(FALSE);
		GetDlgItem(IDC_SELLRADIO)->EnableWindow(FALSE);
		GetDlgItem(IDC_TOMATCHRADIO)->EnableWindow(FALSE);
	}

	InitializeExecutions();
	PopulateExecCombo();

	DWORD style = m_ExecDataListCtrl.GetExtendedStyle();
	style |= LVS_EX_FULLROWSELECT;
	style |= LVS_EX_GRIDLINES;
	style |= LVS_EX_DOUBLEBUFFER;
	m_ExecDataListCtrl.SetExtendedStyle(style);

	m_ExecDataListCtrl.InsertColumn(0,"API Function", LVCFMT_LEFT, 110, 0);
	m_ExecDataListCtrl.InsertColumn(1,"Value", LVCFMT_LEFT, 110, 1);

	InitializeDataCtrlRows();

	account = L_GetAccount();
	account->L_Attach(this);

	return TRUE;
}

void ExecutionDlg::DoDataExchange(CDataExchange* pDX)
{
	__super::DoDataExchange(pDX);

	DDX_Control(pDX, IDC_EXECDATALIST, m_ExecDataListCtrl);
	DDX_Control(pDX, IDC_EXECUTIONCOMBO, m_ExecCombo);
	DDX_Radio(pDX, IDC_ALLRADIO, m_DispType);
}

void ExecutionDlg::InitializeExecutions()
{
	switch(m_ExecutionsSrc)
	{
	case POSITION_EXECUTIONS:
		{
			if (position)
			{
				m_AllExecutions.clear();
				m_AllExecutions.insert(m_AllExecutions.begin(), position->executions_begin(), position->executions_end());

				m_BuyExecutions.clear();
				m_BuyExecutions.insert(m_BuyExecutions.begin(), position->executions_buy_begin(), position->executions_buy_end());

				m_SellExecutions.clear();
				m_SellExecutions.insert(m_SellExecutions.begin(), position->executions_sell_begin(), position->executions_sell_end());

				m_ToMatchExecutions.clear();
				m_ToMatchExecutions.insert(m_ToMatchExecutions.begin(), position->executions_to_match_begin(), position->executions_to_match_end());
			}
		}
		break;
	case ORDER_EXECUTIONS:
		{
			if (order)
			{
				m_AllExecutions.clear();
				m_AllExecutions.insert(m_AllExecutions.begin(), order->executions_begin(), order->executions_end());
			}
		}
		break;
	}
}

void ExecutionDlg::InitializeDataCtrlRows()
{
	for (int i = 0; i < END_OF_VALUES; ++i)
	{
		m_ExecDataListCtrl.InsertItem(i,APIFunctions[i]);
	}
}

void ExecutionDlg::UpdateValues()
{
	for (int i = 0; i < END_OF_VALUES; ++i)
	{
		m_ExecDataListCtrl.SetItemText(i, 1, GetTextForFunction(i));
	}
}

void ExecutionDlg::PopulateExecCombo()
{
	Executions executionsToUse;
	CString comboItem;
	int itemCount = 0;

	switch(m_DispType)
	{
	case ALL_EXEC:
		executionsToUse.insert(executionsToUse.begin(), m_AllExecutions.begin(), m_AllExecutions.end());
		break;
	case BUY_EXEC:
		executionsToUse.insert(executionsToUse.begin(), m_BuyExecutions.begin(), m_BuyExecutions.end());
		break;
	case SELL_EXEC:
		executionsToUse.insert(executionsToUse.begin(), m_SellExecutions.begin(), m_SellExecutions.end());
		break;
	case TO_MATCH_EXEC:
		executionsToUse.insert(executionsToUse.begin(), m_ToMatchExecutions.begin(), m_ToMatchExecutions.end());
		break;
	}

	while (m_ExecCombo.GetCount() > 0)
	{
		m_ExecCombo.DeleteString(0);
	}

	for (Executions::iterator it(executionsToUse.begin()), itend(executionsToUse.end());
		it != itend; ++it, ++itemCount)
	{
		comboItem.Format("%d - %.2f %d", itemCount, it->TotalPrice(), it->Shares());
		m_ExecCombo.InsertString(itemCount,comboItem);
	}
}

void ExecutionDlg::SetAPIFunctions()
{
	memset(APIFunctions,NULL,sizeof(APIFunctions));

	strcpy_s(APIFunctions[TOTAL_PRICE], "Total Price");
	strcpy_s(APIFunctions[AVERAGE_PRICE], "Average Price");
	strcpy_s(APIFunctions[MONEY_INVESTED], "Money Invested");
	strcpy_s(APIFunctions[SHARES], "Shares");
	strcpy_s(APIFunctions[SIDE], "Side");
	strcpy_s(APIFunctions[LIQUIDITY], "Liquidity");
	strcpy_s(APIFunctions[IS_OVERNIGHT], "Is Overnight");
	strcpy_s(APIFunctions[MARKET], "Market");
	strcpy_s(APIFunctions[CONTRA], "Contra");
	strcpy_s(APIFunctions[EXECUTION_TIME], "Execution Time");
	strcpy_s(APIFunctions[EXECUTION_TIME_MILLIS], "Execution Time Millis");
}

CString ExecutionDlg::GetTextForFunction(int function)
{
	CString retString = "";

	switch (function)
	{
	case TOTAL_PRICE:
		{
			retString.Format("%.2f", m_pExecution->TotalPrice());
		}
		break;
	case AVERAGE_PRICE:
		{
			retString.Format("%.2f", m_pExecution->AveragePrice());
		}
		break;
	case MONEY_INVESTED:
		{
			retString.Format("%.2f", m_pExecution->MoneyInvested());
		}
		break;
	case SHARES:
		{
			retString.Format("%d", m_pExecution->Shares());
		}
		break;
	case SIDE:
		{
			retString = m_pExecution->Side();
		}
		break;
	case LIQUIDITY:
		{
			retString = m_pExecution->Liquidity();
		}
		break;
	case IS_OVERNIGHT:
		{
			if (m_pExecution->IsOvernight())
			{
				retString = "Yes";
			}
			else
			{
				retString = "No";
			}
		}
		break;
	case MARKET:
		{
			retString = m_pExecution->Market().c_str();
		}
		break;
	case CONTRA:
		{
			retString = m_pExecution->Contra().c_str();
		}
		break;
	case EXECUTION_TIME:
		{
			retString.Format("%d", m_pExecution->ExecutionTime());
		}
		break;
	case EXECUTION_TIME_MILLIS:
		{
			retString.Format("%d", m_pExecution->ExecutionTimeMillis());
		}
		break;
	}

	return retString;
}

//L_Observer
void ExecutionDlg::HandleMessage(L_Message const *pMsg)
{
	switch (pMsg->L_Type())
	{
	case L_MsgOrderChange::id:
		{
			bool doUpdate = false;
			L_MsgOrderChange const *pMsgOrderChange = static_cast<L_MsgOrderChange const *>(pMsg);

			switch (m_ExecutionsSrc)
			{
			case POSITION_EXECUTIONS:
				if (position && !strcmp(pMsgOrderChange->L_Symbol(), position->L_Symbol()))
				{
					doUpdate = true;
				}
				break;
			case ORDER_EXECUTIONS:
				if (order && (pMsgOrderChange->L_OrderId() == order->L_OrderId()))
				{
					doUpdate = true;
				}
				break;
			}

			if (doUpdate)
			{
				InitializeExecutions();
				PopulateExecCombo();
			}
		}
		break;
	}
}

BEGIN_MESSAGE_MAP(ExecutionDlg, CModelessDialog)
	ON_WM_SIZE()
	ON_BN_CLICKED(IDC_ALLRADIO, OnBnClickedAllRadio)
	ON_BN_CLICKED(IDC_BUYRADIO, OnBnClickedBuyRadio)
	ON_BN_CLICKED(IDC_SELLRADIO, OnBnClickedSellRadio)
	ON_BN_CLICKED(IDC_TOMATCHRADIO, OnBnClickedToMatchRadio)
	ON_CBN_SELCHANGE(IDC_EXECUTIONCOMBO, OnCbnSelchangeExecutionsCombo)
END_MESSAGE_MAP()

// ExecutionDlg message handlers

void ExecutionDlg::OnSize(UINT nType, int cx, int cy)
{
	__super::OnSize(nType, cx, cy);

	ResizeControls();
}

void ExecutionDlg::ResizeControls()
{
	if (m_hWnd && m_ExecDataListCtrl.m_hWnd)
	{
		RECT Rect;
		GetClientRect(&Rect);

		RECT ctrlRect;
		m_ExecDataListCtrl.GetWindowRect(&ctrlRect);
		ScreenToClient(&ctrlRect);

		Rect.top = ctrlRect.top;

		m_ExecDataListCtrl.MoveWindow(&Rect);
	}
}

void ExecutionDlg::OnBnClickedAllRadio()
{
	if (m_DispType != ALL_EXEC)
	{
		m_DispType = ALL_EXEC;

		PopulateExecCombo();
	}
}

void ExecutionDlg::OnBnClickedBuyRadio()
{
	if (m_DispType != BUY_EXEC)
	{
		m_DispType = BUY_EXEC;

		PopulateExecCombo();
	}
}

void ExecutionDlg::OnBnClickedSellRadio()
{
	if (m_DispType != SELL_EXEC)
	{
		m_DispType = SELL_EXEC;

		PopulateExecCombo();
	}
}

void ExecutionDlg::OnBnClickedToMatchRadio()
{
	if (m_DispType != TO_MATCH_EXEC)
	{
		m_DispType = TO_MATCH_EXEC;

		PopulateExecCombo();
	}
}

void ExecutionDlg::OnCbnSelchangeExecutionsCombo()
{
	size_t sel = size_t(m_ExecCombo.GetCurSel());

	if (m_pExecution)
	{
		delete m_pExecution;
		m_pExecution = NULL;
	}

	switch (m_DispType)
	{
	case ALL_EXEC:
		if (sel < m_AllExecutions.size())
		{
			m_pExecution = new C_Execution(m_AllExecutions[sel]);
		}
		break;
	case BUY_EXEC:
		if (sel < m_BuyExecutions.size())
		{
			m_pExecution = new C_Execution(m_BuyExecutions[sel]);
		}
		break;
	case SELL_EXEC:
		if (sel < m_SellExecutions.size())
		{
			m_pExecution = new C_Execution(m_SellExecutions[sel]);
		}
		break;
	case TO_MATCH_EXEC:
		if (sel < m_ToMatchExecutions.size())
		{
			m_pExecution = new C_Execution(m_ToMatchExecutions[sel]);
		}
		break;
	}

	if (m_pExecution)
	{
		UpdateValues();
	}
}
